package com.eternal.device.model;

import android.Manifest;
import android.animation.ValueAnimator;
import android.app.Application;
import androidx.lifecycle.MutableLiveData;
import android.content.Context;
import android.location.LocationManager;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentActivity;

import com.alibaba.android.arouter.facade.Postcard;
import com.alibaba.android.arouter.facade.callback.NavCallback;
import com.alibaba.android.arouter.launcher.ARouter;
import com.eternal.base.concat.BluetoothEvent;
import com.eternal.base.concat.DeviceIndex;
import com.eternal.base.data.DeviceRepository;
import com.eternal.base.data.ble.BleServer;
import com.eternal.base.exception.NotCloseScanException;
import com.eternal.base.exception.NotEnableBluetoothException;
import com.eternal.base.global.ActivityEvent;
import com.eternal.base.global.BluetoothKey;
import com.eternal.base.router.RouterActivityPath;
import com.eternal.base.utils.CustomToastUtils;
import com.eternal.device.ChooseActivity;
import com.eternal.device.DeviceActivity;
import com.eternal.device.GuideActivity;
import com.eternal.device.R;
import com.eternal.device.exception.NoPermissionException;
import com.eternal.framework.binding.command.BindingAction;
import com.eternal.framework.binding.command.BindingCommand;
import com.eternal.framework.bus.Messenger;
import com.eternal.framework.component.AppManager;
import com.eternal.framework.component.BaseViewModel;
import com.eternal.framework.utils.KLog;
import com.eternal.framework.utils.RxUtils;
import com.eternal.framework.utils.Utils;
import com.tbruyelle.rxpermissions2.RxPermissions;

import java.util.List;

import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

import static com.eternal.framework.utils.Utils.getString;

/**
 * Created by Administrator
 * On 2020/4/26
 * Description:
 *
 * @author Administrator
 */
public class AddModel extends BaseViewModel {
    public MutableLiveData<Boolean> minVisible = new MutableLiveData<>();
    public MutableLiveData<Boolean> normalVisible = new MutableLiveData<>();
    public MutableLiveData<Boolean> maxVisible = new MutableLiveData<>();
    public MutableLiveData<Boolean> btnVisible = new MutableLiveData<>();
    public MutableLiveData<Integer> state = new MutableLiveData<>();
    public MutableLiveData<String> stateText = new MutableLiveData<>();
    public MutableLiveData<Integer> btnText = new MutableLiveData<>();

    private Disposable scan;
    private int index;
    private boolean isConnected;
    private DeviceRepository repository;
    private ValueAnimator animator;
    private byte deviceType;

    public AddModel(@NonNull Application application) {
        super(application);
        minVisible.setValue(false);
        normalVisible.setValue(false);
        maxVisible.setValue(false);
        index = -1;
        isConnected = false;
        animator = ValueAnimator.ofInt(0, 4);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int state = (int) animation.getAnimatedValue();
                if (state == 0) {
                    maxVisible.setValue(false);
                    normalVisible.setValue(false);
                    minVisible.setValue(false);
                } else if (state == 1) {
                    minVisible.setValue(true);
                } else if (state == 2) {
                    normalVisible.setValue(true);
                } else {
                    maxVisible.setValue(true);
                }
            }
        });
        animator.setRepeatCount(-1);
        animator.setDuration(2000);
    }

    public BindingCommand<Void> onBack = new BindingCommand<>(new BindingAction() {
        @Override
        public void call() {
            closeScan();
            Postcard postcard;
            if (deviceType == BluetoothKey.DEVICE_TYPE_E) {
               postcard= ARouter.getInstance().build(RouterActivityPath.Device.PAGE_GUIDE)
                        .withByte(GuideActivity.PAGE_TYPE,(byte)0x01);

            } else {
                postcard = ARouter.getInstance().build(RouterActivityPath.Device.PAGE_CHOOSE);
                if (deviceType == BluetoothKey.DEVICE_TYPE_A) {
                    postcard.withByte(ChooseActivity.PAGE_TYPE,(byte) 0x01);
                }
            }
            postcard.withTransition(R.anim.left_in, R.anim.right_out)
                    .navigation(AppManager.getAppManager().currentActivity(), new NavCallback() {
                        @Override
                        public void onArrival(Postcard postcard) {
                            finish();
                        }
                    });
        }
    });

    public BindingCommand<Void> onConfirm = new BindingCommand<>(new BindingAction() {
        @Override
        public void call() {
            if (!isConnected) {// 返回到上页
                onBack.execute();
            } else { // 连接成功，返回设备列表
                pushToMain();
            }
        }
    });

    public BindingCommand<Void> onCancel = new BindingCommand<>(new BindingAction() {
        @Override
        public void call() {
            if (isConnected) {
                pushToMain();
            } else {
                Messenger.getDefault().send(AddModel.this, DeviceActivity.SHOW_DIALOG);
            }
        }
    });

    public void pushToMain(){
        closeScan();
        ARouter.getInstance().build(RouterActivityPath.Main.PAGE_MAIN)
                .withTransition(R.anim.left_in, R.anim.right_out)
                .withInt(ActivityEvent.DEVICE_INDEX, index)
                .withAction(ActivityEvent.ACTION_ADD_DEVICE)
                .navigation(AppManager.getAppManager().currentActivity(), new NavCallback() {
                    @Override
                    public void onArrival(Postcard postcard) {
                        finish();
                        AppManager.getAppManager().finishActivity(GuideActivity.class);
                        AppManager.getAppManager().finishActivity(ChooseActivity.class);
                    }
                });
    }

    public void init(final DeviceRepository repository, byte deviceType) {
        this.repository = repository;
        this.deviceType = deviceType;
        scanAndConnect();
    }

    private void scanAndConnect() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !isLocationEnabled()) {
            scanEnd(false, "Before you continue, AC Infinity needs to access to your location. Turn on Location Service in your device settings.");
            return;
        }
        scan = new RxPermissions((FragmentActivity) AppManager.getAppManager().currentActivity())
                .request(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
                .toList()
                .flatMap(new Function<List<Boolean>, SingleSource<DeviceIndex>>() {
                    @Override
                    public SingleSource<DeviceIndex> apply(List<Boolean> booleans) throws Exception {
                        if (booleans.get(0)) {
                            return repository.scanConnectAndSave(deviceType);
                        }
                        throw new NoPermissionException();
                    }
                })
                .compose(RxUtils.<DeviceIndex>bindToLifecycle(getLifecycleProvider()))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) {
                        scanStart();
                    }
                })
                .subscribe(new Consumer<DeviceIndex>() {
                    @Override
                    public void accept(DeviceIndex info) {
                        index = info.index;
                        isConnected = true;
                        scanEnd(true, Utils.getString(R.string.tip_connect_success, info.typeName, info.name));
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) {
                        if (throwable instanceof NoPermissionException) {
                            CustomToastUtils.showCenterRoundRectToast(Utils.getContext(), "Location Service not authorized");
                        } else if (throwable instanceof NotEnableBluetoothException) {
                            scanEnd(false, Utils.getString(R.string.err_not_enable_blue));
                        } else {
                            scanEnd(false, Utils.getString(R.string.err_no_scanned_device));
                        }
                        throwable.printStackTrace();
                        KLog.e(throwable);
                    }
                });
    }

    private boolean isLocationEnabled() {
        LocationManager lm = (LocationManager) Utils.getApp().getSystemService(Context.LOCATION_SERVICE);
        return lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
                || lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    private void scanStart() {
        if (!animator.isStarted()) {
            btnVisible.setValue(false);
            stateText.setValue(getString(R.string.tip_device_connecting));
            state.setValue(0);
            animator.start();
        }
    }

    private void scanEnd(boolean success, String tip) {
        animator.end();
        if (success) {
            state.setValue(R.mipmap.connect_success);
            btnText.setValue(R.mipmap.ic_done);
        } else {
            state.setValue(R.mipmap.connect_fail);
            btnText.setValue(R.mipmap.ic_ok);
        }
        btnVisible.setValue(true);
        stateText.setValue(tip);
        maxVisible.setValue(false);
        normalVisible.setValue(false);
        minVisible.setValue(false);
    }

    private void closeScan() {
        if (scan != null) {
            scan.dispose();
            scan = null;
        }
        repository.closeScan();
    }
}
